import java.awt.image.BufferedImage;

public class IPWindow
{
	// The frame handles window events.
	public IPFrame frame;

	public ROI roi;

	// This is the backup image for the undo operation.
	// todo: change this into a stack of undo'able items
	public ImageData backupImage;

	public ImageApplication app;
	public int windowID;

	public ImageApplication getImageApp()
	{
		return app;
	}

	public ROI getROI() { return roi; }

	public ImageData getActiveImage()
	{
		if (roi == null)
		{
			return null;
		}
		else
		{
			return roi.getOriginalImage();
		}
	}

	public boolean hasActiveImage()
	{
		return getActiveImage() != null;
	}

	/**
	 * Create window without any image loaded.
	 * This should only be called by the application.
	 */
	public IPWindow(ImageApplication _app)
	{
		app = _app;
		frame = new IPFrame(this);
		roi = null;
		backupImage = null;
		frame.setVisible(true);
	}

	/**
	 * Create window using specified image and ROI
	 * This should only be called by the application.
	 */
	public IPWindow(ImageApplication _app,
			ImageData img, int x, int y, int w, int h)
	{
		app = _app;
		roi = new ROI(img, x, y, w, h);
		frame = new IPFrame(this);
		frame.setVisible(true);
		//frame.repaint();
		p.print("creating window with roi specified");
	}

	/**
	 * Window ID set
	 */
	public void setWindowId(int id)
	{
		windowID = id;
		frame.setTitle("ImageApp - winid: " + id);
	} 
	public int getWindowId() { return windowID; }

	/**
	 * Called when a new image is opened.
	 */
	public void loadNewImage(String filename)
	{
		roi = new ROI(filename);
		frame.enableSaveMenuItems(hasActiveImage());
	}

	/**
	 * Called by application to signal this window will close.
	 */
	public void notifyWindowIsClosing()
	{
		// Free image resources
		

		// Hide frame and free resources
		frame.setVisible(false);
		frame.dispose();
	}

	/**
	 * Called by frame when save is invoked.
	 */
	public void saveActiveImage(String filename)
	{
		if (hasActiveImage())
		{
			getActiveImage().saveImage(filename);
		}
		else
		{
			p.print("No image to save.");
		}
	}

	public void applyThreshold(int value)
	{
		if (hasActiveImage())
		{
			backupImage();
			app.threshold(value, this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}

	public void applyImageNegative()
	{
		if (hasActiveImage())
		{
			backupImage();
			app.imageNegative(this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}
	
	public void applyMedianFileter(){
		if (hasActiveImage()){
			backupImage();
			app.medianFilter(this);
			frame.repaint();
		}
	}

	public void applyContrastStretch(Boolean contrastInc)
	{
		if (hasActiveImage())
		{
			backupImage();
			app.contrastStretch(contrastInc, this);
			frame.repaint();
		}
		else
		{
			p.print("No image to operate on.");
		}
	}

	/**
	 * Create new ipimage from existing one.
	 *
	 */
	public void backupImage()
	{
		backupImage = getActiveImage().clone();
	}

	public void restoreImage()
	{
		if (backupImage != null)
		{
			// Create new ipimage from existing one.
			roi = new ROI(backupImage, 0, 0,
					backupImage.getWidth(), backupImage.getHeight());
			frame.repaint();
		}
		else
		{
			p.print("No backup image found.");
		}
	}

	/**
	 * Convenience function to change activeImage. Please backupImage() first so Undo works.
	 * @param new_image
	 */
	void setActiveImage(ImageData new_image) {
		int[] new_image_pixels = new int[new_image.getWidth() * new_image.getHeight()];
		new_image.getPixels(new_image_pixels, 0, 0, new_image.getWidth(), new_image.getHeight());
		getActiveImage().setPixels(new_image_pixels, 0, 0, new_image.getWidth(), new_image.getHeight());
	}
	
	// Boni: We probably should not be setting the render image directly.
	// Otherwise, the pixel data will be out of sync.
	// TODO: Refactor this so that either:
	// 1) setting render image updates pixel data, or
	// 2) this method (or caller of this method) should set pixel data instead
	void setActiveImg(BufferedImage image){
		getActiveImage().setImageData(image);
	}
	
}

